package com.bozhong.config.parser;

import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author fupan
 */
public class NacosDataXmlParser extends AbstractNacosDataParser {
	public NacosDataXmlParser() {
		super("xml");
	}

	@Override
	protected Map<String, Object> doParse(String data) throws IOException {
		if (StringUtils.isEmpty(data)) {
			return null;
		} else {
			Map<String, Object> map = this.parseXml2Map(data);
			return this.reloadMap(map);
		}
	}

	private Map<String, Object> parseXml2Map(String xml) throws IOException {
		xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", "");
		LinkedHashMap map = new LinkedHashMap(32);

		try {
			DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document document = documentBuilder.parse(new InputSource(new StringReader(xml)));
			if (null == document) {
				return null;
			} else {
				this.parseNodeList(document.getChildNodes(), map, "");
				return map;
			}
		} catch (Exception var5) {
			throw new IOException("The xml content parse error.", var5.getCause());
		}
	}

	private void parseNodeList(NodeList nodeList, Map<String, Object> map, String parentKey) {
		if (nodeList != null && nodeList.getLength() >= 1) {
			parentKey = parentKey == null ? "" : parentKey;

			for(int i = 0; i < nodeList.getLength(); ++i) {
				Node node = nodeList.item(i);
				String value = node.getNodeValue();
				value = value == null ? "" : value.trim();
				String name = node.getNodeName();
				name = name == null ? "" : name.trim();
				if (!StringUtils.isEmpty(name)) {
					String key = StringUtils.isEmpty(parentKey) ? name : parentKey + "." + name;
					NamedNodeMap nodeMap = node.getAttributes();
					this.parseNodeAttr(nodeMap, map, key);
					if (node.getNodeType() == 1 && node.hasChildNodes()) {
						this.parseNodeList(node.getChildNodes(), map, key);
					} else if (value.length() >= 1) {
						map.put(parentKey, value);
					}
				}
			}

		}
	}

	private void parseNodeAttr(NamedNodeMap nodeMap, Map<String, Object> map, String parentKey) {
		if (null != nodeMap && nodeMap.getLength() >= 1) {
			for(int i = 0; i < nodeMap.getLength(); ++i) {
				Node node = nodeMap.item(i);
				if (null != node && node.getNodeType() == 2 && !StringUtils.isEmpty(node.getNodeName()) && !StringUtils.isEmpty(node.getNodeValue())) {
					map.put(String.join(".", parentKey, node.getNodeName()), node.getNodeValue());
				}
			}

		}
	}
}
